package com.ruoyi.ucar.service.impl;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.net.URLEncoder;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.lang.UUID;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.obs.services.ObsClient;
import com.obs.services.model.AccessControlList;
import com.obs.services.model.ObsObject;
import com.obs.services.model.PutObjectRequest;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.ucar.boreq.SysFileBoReq;
import com.ruoyi.ucar.boresp.ObsImageBoResp;
import com.ruoyi.ucar.domain.SysFileData;
import com.ruoyi.ucar.domain.SysFileMain;
import com.ruoyi.ucar.mapper.SysFileDataMapper;
import com.ruoyi.ucar.mapper.SysFileMainMapper;
import com.ruoyi.ucar.service.ISysFileMainService;
import com.ruoyi.ucar.util.CommonUtil;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;

/**
 * 文件附件主Service业务层处理
 * 
 * @author sungangbin
 * @date 2025-05-13
 */
@Service
public class SysFileMainServiceImpl extends ServiceImpl<SysFileMainMapper, SysFileMain> implements ISysFileMainService
{
    @Autowired
    private SysFileMainMapper sysFileMainMapper;

    @Autowired
    private SysFileDataMapper sysFileDataMapper;

    @Autowired
    private ObsClient obsClient;

    @Value("${ucar.obs.bucketName}")
    private String bucketName;

    /**
     * 查询文件附件主
     * 
     * @param id 文件附件主主键
     * @return 文件附件主
     */
    @Override
    public SysFileMain selectSysFileMainById(Long id)
    {
        return sysFileMainMapper.selectSysFileMainById(id);
    }

    /**
     * 查询文件附件主列表
     * 
     * @param sysFileMain 文件附件主
     * @return 文件附件主
     */
    @Override
    public List<SysFileMain> selectSysFileMainList(SysFileMain sysFileMain)
    {
        return sysFileMainMapper.selectSysFileMainList(sysFileMain);
    }

    /**
     * 新增文件附件主
     * 
     * @param sysFileMain 文件附件主
     * @return 结果
     */
    @Override
    public int insertSysFileMain(SysFileMain sysFileMain)
    {
        return sysFileMainMapper.insertSysFileMain(sysFileMain);
    }

    /**
     * 修改文件附件主
     * 
     * @param sysFileMain 文件附件主
     * @return 结果
     */
    @Override
    public int updateSysFileMain(SysFileMain sysFileMain)
    {
        return sysFileMainMapper.updateSysFileMain(sysFileMain);
    }

    /**
     * 批量删除文件附件主
     * 
     * @param ids 需要删除的文件附件主主键
     * @return 结果
     */
    @Override
    public int deleteSysFileMainByIds(Long[] ids)
    {
        return sysFileMainMapper.deleteSysFileMainByIds(ids);
    }

    /**
     * 删除文件附件主信息
     * 
     * @param id 文件附件主主键
     * @return 结果
     */
    @Override
    public int deleteSysFileMainById(Long id)
    {
        return sysFileMainMapper.deleteSysFileMainById(id);
    }


    /**
     * 保存文件附件数据
     * @param sysFileBoReq
     * @return
     */
    @Transactional
    @Override
    public String saveSysFile(SysFileBoReq sysFileBoReq) {
            String sysFileMainUUID= UUID.randomUUID().toString();
            SysFileMain sysFileMain=new SysFileMain();
            sysFileMain.setFileMainUuid(sysFileMainUUID);
            sysFileMain.setDeleteFlag(1L);
            sysFileMain.setCreatedBy("admin");
            this.save(sysFileMain);
            SysFileData sysFileData=CommonUtil.objToObj(sysFileBoReq, SysFileData.class);
            sysFileData.setFileDataUuid(UUID.randomUUID().toString());
            sysFileData.setFileMainUuid(sysFileMainUUID);
            sysFileData.setDeleteFlag(1L);
            sysFileData.setCreatedBy("admin");
            sysFileDataMapper.insert(sysFileData);
            return sysFileMainUUID;
    }

    @Override
    public String saveSysFile(MultipartFile file) throws IOException {
        String sysFileMainUUID= UUID.randomUUID().toString();
        SysFileMain sysFileMain=new SysFileMain();
        sysFileMain.setFileMainUuid(sysFileMainUUID);
        sysFileMain.setDeleteFlag(1L);
        sysFileMain.setCreatedBy(SecurityUtils.getUsername());
        this.save(sysFileMain);
        SysFileData sysFileData=new SysFileData();
        String fileOldName=file.getOriginalFilename();
        String fileNewName=UUID.randomUUID().toString();
        String fileName = fileNewName+fileOldName ;
        sysFileData.setFileOldName(fileOldName);
        sysFileData.setFileNewName(fileName);
        InputStream inputStream=file.getInputStream();
        String fileURl = this.obsUploadFile(fileName,inputStream,AccessControlList.REST_CANNED_PUBLIC_READ);
        sysFileData.setFileUrl(fileURl);
        sysFileData.setSort(0l);
        sysFileData.setFileSize(new Long(file.getSize()).toString());
        sysFileData.setFileFormat(FileNameUtil.extName(fileOldName));
        sysFileData.setFileDataUuid(UUID.randomUUID().toString());
        sysFileData.setFileMainUuid(sysFileMainUUID);
        sysFileData.setDeleteFlag(1L);
        sysFileData.setCreatedBy(SecurityUtils.getUsername());
        sysFileData.setFileType("normalFile");
        sysFileDataMapper.insert(sysFileData);
        inputStream.close();
        return sysFileMainUUID;
    }


    @Override
    public SysFileData saveSysFile(MultipartFile file,AccessControlList accessControlList) throws IOException {
        String sysFileMainUUID= UUID.randomUUID().toString();
        SysFileMain sysFileMain=new SysFileMain();
        sysFileMain.setFileMainUuid(sysFileMainUUID);
        sysFileMain.setDeleteFlag(1L);
        sysFileMain.setCreatedBy(SecurityUtils.getUsername());
        this.save(sysFileMain);
        SysFileData sysFileData=new SysFileData();
        String fileOldName=file.getOriginalFilename();
        String fileNewName=UUID.randomUUID().toString();
        String fileName = fileNewName+fileOldName ;
        sysFileData.setFileOldName(fileOldName);
        sysFileData.setFileNewName(fileName);
        InputStream inputStream=file.getInputStream();
        String fileURl = this.obsUploadFile(fileName,inputStream,accessControlList);
        sysFileData.setFileUrl(fileURl);
        sysFileData.setSort(0l);
        sysFileData.setFileSize(new Long(file.getSize()).toString());
        sysFileData.setFileFormat(FileNameUtil.extName(fileOldName));
        sysFileData.setFileDataUuid(UUID.randomUUID().toString());
        sysFileData.setFileMainUuid(sysFileMainUUID);
        sysFileData.setDeleteFlag(1L);
        sysFileData.setCreatedBy(SecurityUtils.getUsername());
        sysFileData.setFileType("normalFile");
        sysFileDataMapper.insert(sysFileData);
        inputStream.close();
        return sysFileData;
    }

    @Override
    public SysFileMain saveSysFile(List<MultipartFile> files, AccessControlList accessControlList) throws IOException {
        String sysFileMainUUID= UUID.randomUUID().toString();
        SysFileMain sysFileMain=new SysFileMain();
        sysFileMain.setFileMainUuid(sysFileMainUUID);
        sysFileMain.setDeleteFlag(1L);
        sysFileMain.setCreatedBy(SecurityUtils.getUsername());
        this.save(sysFileMain);
        List<String> fileUrls=new ArrayList<>();
        for(MultipartFile file:files) {
            SysFileData sysFileData = new SysFileData();
            String fileOldName = file.getOriginalFilename();
            String fileNewName = UUID.randomUUID().toString();
            String fileName = fileNewName + fileOldName;
            sysFileData.setFileOldName(fileOldName);
            sysFileData.setFileNewName(fileName);
            InputStream inputStream = file.getInputStream();
            String fileURl = this.obsUploadFile(fileName, inputStream, accessControlList);
            fileUrls.add(fileURl);
            sysFileData.setFileUrl(fileURl);
            sysFileData.setSort(0l);
            sysFileData.setFileSize(new Long(file.getSize()).toString());
            sysFileData.setFileFormat(FileNameUtil.extName(fileOldName));
            sysFileData.setFileDataUuid(UUID.randomUUID().toString());
            sysFileData.setFileMainUuid(sysFileMainUUID);
            sysFileData.setDeleteFlag(1L);
            sysFileData.setCreatedBy(SecurityUtils.getUsername());
            sysFileData.setFileType("normalFile");
            sysFileDataMapper.insert(sysFileData);
            inputStream.close();
        }
        sysFileMain.setFileUrls(fileUrls);
        return sysFileMain;
    }

    @Override
    @Transactional
    public String batchSaveSysFile(List<SysFileBoReq> sysFileBoReqList) {
        int batchSaveResult=0;
        String sysFileMainUUID= UUID.randomUUID().toString();
        SysFileMain sysFileMain=new SysFileMain();
        sysFileMain.setFileMainUuid(sysFileMainUUID);
        sysFileMain.setDeleteFlag(1L);
        sysFileMain.setCreatedBy(SecurityUtils.getUsername());
        this.save(sysFileMain);
        for (SysFileBoReq sysFileBoReq:
                sysFileBoReqList) {
            SysFileData sysFileData=CommonUtil.objToObj(sysFileBoReq, SysFileData.class);
            sysFileData.setFileDataUuid(UUID.randomUUID().toString());
            sysFileData.setFileMainUuid(sysFileMainUUID);
            sysFileData.setDeleteFlag(1L);
            sysFileData.setCreatedBy(SecurityUtils.getUsername());
            batchSaveResult+=sysFileDataMapper.insert(sysFileData);
        }
        return sysFileMainUUID;
    }

    @Override
    public String obsUploadFile(String fileName, InputStream fileInputStream, AccessControlList accessControlList) {
        PutObjectRequest request = new PutObjectRequest(
                bucketName,
                fileName,
                fileInputStream
        );
        request.setAcl(accessControlList);
        return obsClient.putObject(request).getObjectUrl();
    }

    @Override
    public void obsDownLoadFile(String fileMainUuid, HttpServletResponse response) {
        SysFileData sysFileData = sysFileDataMapper.selectOne(
                new LambdaQueryWrapper<SysFileData>().eq(SysFileData::getFileMainUuid,fileMainUuid)
                        .eq(SysFileData::getDeleteFlag,1l).eq(SysFileData::getSort,0));
        if(sysFileData!=null ) {
            // 初始化OBS客户端
            try  {
                // 获取OBS对象
                String objectKey=sysFileData.getFileNewName();
                ObsObject obsObject = obsClient.getObject(bucketName, objectKey);
                // 设置响应头（强制下载）
                response.setContentType("application/octet-stream");
                String encodedFileName = URLEncoder.encode(objectKey, "UTF-8");
                response.setHeader("Content-Disposition",
                        "attachment; filename*=UTF-8''" + encodedFileName);

                // 流式传输（避免内存溢出）
                try (InputStream obsStream = obsObject.getObjectContent();
                     OutputStream os = response.getOutputStream()) {
                    IOUtils.copy(obsStream, os);  // Apache Commons IO
                }
            }   catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

        }
    }

    @Override
    public void obsDownLoadFile2(String fileDataUuid, HttpServletResponse response) {
       SysFileData sysFileData = sysFileDataMapper.selectOne(
                new LambdaQueryWrapper<SysFileData>().eq(SysFileData::getFileDataUuid,fileDataUuid)
                        .eq(SysFileData::getDeleteFlag,1l));
        if(sysFileData!=null ) {
            // 初始化OBS客户端
            try  {
                // 获取OBS对象
                String objectKey=sysFileData.getFileNewName();
                ObsObject obsObject = obsClient.getObject(bucketName, objectKey);
                // 设置响应头（强制下载）
                response.setContentType("application/octet-stream");
                String encodedFileName = URLEncoder.encode(objectKey, "UTF-8");
                response.setHeader("Content-Disposition",
                        "attachment; filename*=UTF-8''" + encodedFileName);

                // 流式传输（避免内存溢出）
                try (InputStream obsStream = obsObject.getObjectContent();
                     OutputStream os = response.getOutputStream()) {
                     IOUtils.copy(obsStream, os);  // Apache Commons IO
                }
            }   catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

        }
    }

    @Override
    public ObsImageBoResp obsDownloadImageToBase64String(String fileMainUuid) {
        ObsImageBoResp obsImageBoRes=new ObsImageBoResp();
        SysFileData sysFileData = sysFileDataMapper.selectOne(
                new LambdaQueryWrapper<SysFileData>().eq(SysFileData::getFileMainUuid,fileMainUuid)
                        .eq(SysFileData::getDeleteFlag,1l).eq(SysFileData::getSort,0));
        if(sysFileData!=null ) {
                obsImageBoRes.setImageType(sysFileData.getFileFormat());
                // 获取OBS对象
                String objectKey=sysFileData.getFileNewName();
                ObsObject obsObject = obsClient.getObject(bucketName, objectKey);
                InputStream obsStream = obsObject.getObjectContent();
                obsImageBoRes.setBase64String(CommonUtil.convertBase64FromInput(obsStream));
            return obsImageBoRes;
        }else{
            return null;
        }
    }
}
